package com.sx.service.system;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sx.basic.ResponseEntity;
import com.sx.basic.TokenEntity;
import com.sx.basic.enums.HttpMethod;
import com.sx.basic.exception.BasicException;
import com.sx.dto.AdminInfo;
import com.sx.entity.system.AdminEntity;
import com.sx.entity.system.MenuEntity;
import com.sx.entity.system.RoleEntity;
import com.sx.mapper.system.AdminMapper;
import com.sx.basic.BasicService;
import com.sx.basic.impl.BasicServiceImpl;
import com.sx.basic.TokenService;
import com.sx.utils.DateUtils;
import com.sx.utils.PasswordUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author AdinZ
 * @date 2020/11/7 17:57
 */
@Service
public class AdminService extends BasicServiceImpl<AdminMapper,AdminEntity>
        implements BasicService<AdminEntity> , IAdminService {

    @Resource private TokenService tokenService;
    @Resource private IRoleService roleService;
    @Resource private IMenuService menuService;

    /**
     * 管理员登陆
     * @param username 账号
     * @param password 密码
     * @return data 返回token
     */
    @Override
    public ResponseEntity<String> login(String username, String password) {
        if(StringUtils.isEmpty(username))return new ResponseEntity().toError("账号不能空");
        if(StringUtils.isEmpty(password))return toError("密码不能空");
        QueryWrapper wrapper=new QueryWrapper();
        wrapper.eq("username",username);
        AdminEntity entity = this.baseMapper.selectOne(wrapper);
        if(entity==null)return toError("用户不存在");
        if(!StringUtils.equals(entity.getPassword(), PasswordUtils.getInstance().md5(password)))
            return toError("密码错误");

        TokenEntity  tokenEntity=new TokenEntity(entity.getId(), TokenEntity.Type.SYSTEM, TokenEntity.Channel.PC,entity, DateUtils.addHour(1).getTime());
        this.tokenService.tokenGen(tokenEntity);
        return toSuccess("登陆成功",tokenEntity.getToken());
    }

    /**
     * 退出登陆
     * @param token
     * @return
     */
    @Override
    public ResponseEntity logout(String token) {
        if(StringUtils.isEmpty(token))
            return toError();
        this.tokenService.deleteToken(token);
        return toSuccess();
    }

    /**
     * 获取权限资料
     * @param token
     * @return
     */
    @Override
    public ResponseEntity<AdminInfo> getInfo(String token) {
        long uid = this.tokenService.getUid(token);
        AdminInfo adminInfo=this.redisService.get(AdminInfo.KEY,uid);
        if(adminInfo==null) {
            AdminEntity adminEntity = this.getById(uid);
            if (adminEntity == null) return toError("管理员不存在或被禁用");
            RoleEntity roleEntity = this.roleService.get(adminEntity.getRoleId());
            if (roleEntity == null) return toError("还未分配角色权限");
            List<Long> menuIds = roleEntity.getMenuIds();
            adminInfo = new AdminInfo();
            if(menuIds!=null&&menuIds.size()>0) {
                List<MenuEntity> menuEntities = this.menuService.listById(menuIds);
                List<MenuEntity> list = MenuEntity.toChild(menuEntities, 0);
                adminInfo.setMenus(list);
            }

            BeanUtils.copyProperties(adminEntity, adminInfo);
            adminInfo.setRoleName(roleEntity.getRoleName());

            this.redisService.set(AdminInfo.KEY,uid,adminInfo);
        }
        return toSuccess(adminInfo);
    }

    /**
     * 新增或更新管理员
     * @param entity
     * @return
     */
    @Override
    public ResponseEntity putAdmin(AdminEntity entity){
        if(entity.getId()==null){
            QueryWrapper wrapper=new QueryWrapper();
            wrapper.eq("username",entity.getUsername());
            if(this.baseMapper.selectOne(wrapper)!=null){
                return toError("用户名已存在");
            }
            entity.setPassword(PasswordUtils.getInstance().md5(entity.getPassword()));
            this.save(entity);
        }else {
            AdminEntity adminEntity = this.getById(entity.getId());
            if(!StringUtils.equals(adminEntity.getPassword(),entity.getPassword())){
                entity.setPassword(PasswordUtils.getInstance().md5(entity.getPassword()));
            }
            this.updateById(entity);
        }
        this.redisService.delete(AdminInfo.KEY,entity.getId());
        return toSuccess();
    }

    @Override
    public ResponseEntity deleteAdmin(Long[] ids) {
        super.removeByIds(Arrays.asList(ids));
        return toSuccess();
    }


    @Override
    public boolean isAuthority(String token, String method, String requestURI) {
        TokenEntity<AdminEntity> tokenEntity = this.tokenService.getToken(token);
        if(tokenEntity.getData().getRoleId()==0)return true;
        //角色实体
        RoleEntity roleEntity = this.roleService.get(tokenEntity.getData().getRoleId());
        if (roleEntity == null) throw new BasicException(400, "管理员还未分配角色权限");
        //全部的角色菜单id
        List<Long> menuIds = roleEntity.getMenuIds();
        //菜单列表
        List<MenuEntity> list = this.menuService.findMenu(MenuEntity.Action.API);
        if (list == null || list.size() == 0) throw new BasicException(400, "角色没有任何权限");
        for (MenuEntity menu : list) {
            if (!menuIds.contains(menu.getId())) continue;
            //正则匹配url是否有权限
            if (Pattern.matches(menu.getUrl(), requestURI)&&menu.getMethod()== HttpMethod.valueOf(method)) {
                return true;
            }
        }
        throw new BasicException(ResponseEntity.CODE_AUTHOR_FAIL, "权限不足");
    }

    /***
     *
     * @param page
     * @param size
     * @return
     */
    @Override
    public ResponseEntity<List<AdminEntity>> findPage(int page,int size) {
        IPage iPage=new Page(page,size);
        super.page(iPage);
        return toPage(iPage);
    }
}
